﻿using CommunicationLib.Base;
using CommunicationLib.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CommunicationLib
{
    public class Communication : CommunicationBase
    {
        private IPAddress iPAddress= null;
        private int netPort = 0;
        private string comName = "COM1";
        private int comBaudRate = 9600;
        private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

        public event Action<object, CommunicationArgsBase> OnError;
        public event Action<object, DataPackage> OnReceived;



        /// <summary>
        /// 网口通讯模式初始化
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="netPort"></param>
        public void Initiallize(IPAddress ipAddress, int netPort) 
        {
            this.iPAddress = ipAddress;
            this.netPort = netPort;
            CommunicationMode = Enums.CommunicationMode.TCP;
            TcpClient = new System.Net.Sockets.TcpClient();
            Init();
        }
        public  void Initiallize(string comName,int comBaudRate)
        {
            this.comName = comName;
            this.comBaudRate = comBaudRate;
            CommunicationMode = Enums.CommunicationMode.SerialPort;
            SerialPort = new SerialPort(comName, comBaudRate);
            Init();
        }

        /// <summary>
        /// 内部初始化
        /// </summary>
        private void Init()
        {
            //todo

            RingBuffer = new RingBufferManager(65535);
        }

        public ConnectionResult Connect(bool reConnect = false)
        {
            ConnectionResult connectionResult = new ConnectionResult();
            switch (CommunicationMode)
            {
                case Enums.CommunicationMode.TCP:
                    try
                    {
                        if (reConnect)
                        {
                            TcpClient = new TcpClient();
                        }

                        TcpClient.Connect(iPAddress, netPort);//连接TCP
                        connectionResult.Message = "连接成功";
                        connectionResult.Success = true;
                    }
                    catch(Exception ex)
                    {
                        connectionResult.Exception = ex;
                        connectionResult.Message = "连接失败";
                        connectionResult.Success = false;
                    }
                    break;
                case Enums.CommunicationMode.SerialPort:
                    if (SerialPort == null)
                    {
                        SerialPort = new SerialPort(comName,comBaudRate);
                    }
                    try
                    {
                        SerialPort.Open();
                        connectionResult.Message = "连接成功";
                        connectionResult.Success = true;

                    }
                    catch(Exception ex)
                    {
                        connectionResult.Exception = ex;
                        connectionResult.Message = "连接失败";
                        connectionResult.Success = false;
                    }
                    break;
                default: break;
            }

            return connectionResult;
        }

        public ConnectionResult ShakeHands(byte[] finsBytes,int maxMilliseconds = 3000)
        {
            ConnectionResult connectionResult = new ConnectionResult();
            switch (CommunicationMode)
            {
                case Enums.CommunicationMode.TCP:
                    try
                    {
                        if (TcpClient == null || TcpClient.Client.Connected == false) 
                        {
                            connectionResult.Message = "TcpClient为null或无连接";
                            return connectionResult;
                        }

                        Stopwatch stopwatch = Stopwatch.StartNew();
                        var stream = TcpClient.GetStream();
                        stream.WriteAsync(finsBytes, 0, finsBytes.Length);//发送握手指令
                        Thread.Sleep(1);

                        while (stopwatch.ElapsedMilliseconds < maxMilliseconds)
                        {
                            if (TcpClient.Available > 0)
                            {
                                break;
                            }

                            //Thread.Sleep(1);
                        }

                        byte[] receiveBuffer = new byte[TcpClient.Available];
                        stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length);
                        stream.Flush();
                        stopwatch.Stop();
                        connectionResult.Success = true;
                        connectionResult.Content = receiveBuffer;
                    }
                    catch (Exception ex)
                    {
                        connectionResult.Message = ex.Message;
                        connectionResult.Exception = ex;
                    }
                    break;
                case Enums.CommunicationMode.SerialPort:
                    break;
                default:
                    break;
            }

            return connectionResult;
        }

        public override bool Start()
        {
            switch (CommunicationMode)
            {
                case Enums.CommunicationMode.TCP:
                    try
                    {
                        Task.Factory.StartNew(Receive);//接收TCP数据
                        return true;
                    }
                    catch(Exception ex)
                    {
                        OnError?.Invoke(this, new CommunicationArgsBase { Exception = ex, Message = "接收TCP数据发生错误" });

                        return false;
                    }

                case Enums.CommunicationMode.SerialPort:
                    if (SerialPort == null)
                    {
                        OnError?.Invoke(this, new CommunicationArgsBase { Message = "SerialPort没有初始化" });
                    }
                    try
                    {
                        if (SerialPort.IsOpen == false)
                        {
                            SerialPort.Open();
                        }

                        SerialPort.DataReceived -= SerialPort_DataReceived;
                        SerialPort.DataReceived += SerialPort_DataReceived;
                        return true;
                    }
                    catch (Exception ex)
                    {
                        OnError?.Invoke(this, new CommunicationArgsBase { Exception = ex, Message = "打开串口时发生错误" });
                        return false;
                    }
                    
                default: break;
            }

            return false;
        }

        //接收串口数据的回调函数
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                int count = SerialPort.BytesToRead;
                byte[] buffer = new byte[count];
                SerialPort.Read(buffer, 0, count);
                lock(lockRingBuffer)
                {
                    RingBuffer.WriteBuffer(buffer);
                }


                //从环型缓冲区中读取数据

                if (Package.NeedLength == -1)
                {
                    //收到什么是什么
                    lock (lockRingBuffer)
                    {
                        byte[] receiveBuffer = new byte[buffer.Length];
                        RingBuffer.ReadBuffer(receiveBuffer, 0, receiveBuffer.Length);
                        RingBuffer.Clear(receiveBuffer.Length);
                        Package.ReceiveBuffer = receiveBuffer;
                        Package.ReceiveTime = DateTime.Now;
                        OnReceived?.Invoke(this, Package);
                    }
                }
                else if (RingBuffer.DataCount >= Package.NeedLength)
                {
                    lock (lockRingBuffer)
                    {
                        byte[] receiveBuffer = new byte[Package.NeedLength];
                        RingBuffer.ReadBuffer(receiveBuffer, 0, receiveBuffer.Length);
                        RingBuffer.Clear(receiveBuffer.Length);
                        Package.ReceiveBuffer = receiveBuffer;
                        Package.ReceiveTime = DateTime.Now;
                        OnReceived?.Invoke(this, Package);
                    }
                }
            }
            catch (Exception ex)
            {
                OnError?.Invoke(this, new CommunicationArgsBase { Exception = ex, Message = "接收串口数据时发生错误" });
            }
        }

        //接收TCP数据的回调子线程
        private void Receive()
        {
            while(!cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    if (TcpClient == null || TcpClient.Connected == false)
                    {
                        Thread.Sleep(1000);
                        continue;
                    }

                    int count = TcpClient.Available;
                    byte[] buffer = new byte[count];
                    count = TcpClient.Client.Receive(buffer);//此处阻塞
                    byte[] receiveBuffer = buffer.Take(count).ToArray();//实际数据
                    if(receiveBuffer.Length > 0)
                    {
                        lock (lockRingBuffer)
                        {
                            RingBuffer.WriteBuffer(buffer);
                        }

                        //从环型缓冲区中读取数据

                        if(Package.NeedLength == -1)
                        {
                            //收到什么是什么
                            lock (lockRingBuffer)
                            {
                                receiveBuffer = new byte[receiveBuffer.Length];
                                RingBuffer.ReadBuffer(receiveBuffer, 0, receiveBuffer.Length);
                                RingBuffer.Clear(receiveBuffer.Length);
                                Package.ReceiveBuffer = receiveBuffer;
                                Package.ReceiveTime = DateTime.Now;
                                OnReceived?.Invoke(this, Package);
                            }
                        }
                        else if (RingBuffer.DataCount >= Package.NeedLength && Package.NeedLength > 0)
                        {
                            lock (lockRingBuffer)
                            {
                                receiveBuffer = new byte[Package.NeedLength];
                                RingBuffer.ReadBuffer(receiveBuffer, 0, receiveBuffer.Length);
                                RingBuffer.Clear(receiveBuffer.Length);
                                Package.ReceiveBuffer = receiveBuffer;
                                Package.ReceiveTime = DateTime.Now;
                                OnReceived?.Invoke(this, Package);
                            }
                        }

#if DEBUG  //开发时调试用

                        //if (RingBuffer.DataCount >= 0)
                        //{
                        //    lock (lockRingBuffer)
                        //    {
                        //        receiveBuffer = new byte[RingBuffer.DataCount];
                        //        RingBuffer.ReadBuffer(receiveBuffer, 0, receiveBuffer.Length);
                        //        RingBuffer.Clear(receiveBuffer.Length);
                        //        Package.ReceiveBuffer = receiveBuffer;
                        //        Package.ReceiveTime = DateTime.Now;
                        //        OnReceived?.Invoke(this, Package);
                        //    }
                        //}
#endif
                    }
                }
                catch(Exception ex)
                {
                    TcpClient.Client.Shutdown(SocketShutdown.Both);
                    Thread.Sleep(10);
                    TcpClient.Client.Close();
                    OnError?.Invoke(this, new CommunicationArgsBase { Exception = ex, Message = "接收tcp数据时发生错误" });
                }
            }
        }

        public override void Send(DataPackage dataPackage)
        {
            this.Package = dataPackage;

            switch (CommunicationMode)
            {
                case Enums.CommunicationMode.TCP:
                    if (TcpClient != null && TcpClient.Connected)
                    {
                        try
                        {
                            TcpClient.Client.Send(dataPackage.SendBuffer);
                        }
                        catch (Exception ex)
                        {
                            OnError?.Invoke(this, new CommunicationArgsBase { Exception = ex, Message = "发送tcp数据时发生错误" });
                        }
                    }
                    break;
                case Enums.CommunicationMode.SerialPort:
                    if (SerialPort != null && SerialPort.IsOpen)
                    {
                        try
                        {
                            SerialPort.Write(dataPackage.SendBuffer, 0, dataPackage.SendBuffer.Length);
                        }
                        catch (Exception ex)
                        {
                            OnError?.Invoke(this, new CommunicationArgsBase { Exception = ex, Message = "发送串口数据时发生错误" });
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        

        public override bool Stop()
        {
            cancellationTokenSource.Cancel();

            return true;
        }
    }
}
